Python 您所在的位置:网站首页 tkinter gui首次启动慢 Python

Python

2024-07-17 01:07| 来源: 网络整理| 查看: 265

本文总结如何暂停或继续 Tkinter 多线程以及多文件间的调用。

Update: 2022 / 11 / 19

Python | GUI | Tkinter - 4. 多线程以及文件间调用 Tkinter 多线程启用子线程子线程的暂停与重启 Tkinter 文件之间调用参考链接

Tkinter 多线程

参考这里 1

为什么要使用多线程?—— 单线程下,主线程需要运行窗口,如果这个时候点击“确定”按钮,主线程就会去执行 event 方法,而如果 event 方法占用主线程,则原先的运行窗口就会出现 无响应 状态。

比如,按照以下示例运行,

import tkinter as tk class GUI: def __init__(self): self.root = tk.Tk() self.root.title('Title') self.root.geometry("600x300+550+300") self.interface() def interface(self): """"界面编写位置""" self.Button0 = tk.Button(self.root, text="确定", command=self.event) self.Button0.grid(row=0, column=0) self.w1 = tk.Text(self.root, width=80, height=10) self.w1.grid(row=1, column=0) def event(self): '''按钮事件,一直循环''' a = 0 while True: a += 1 self.w1.insert(1.0, str('1') + '\n') if __name__ == '__main__': gui = GUI() gui.root.mainloop()

运行效果如下,

在这里插入图片描述 如果要原先的运行窗口正常显示,那我们就需要用到多线程 ( threading )。

启用子线程

将上面的示例改写,改写为主线程去执行 start 方法,而如果 start 方法中启用 self.T 子线程,子线程调用 event 方法。self.T 子线程作为守护进程,即主进程结束(或者说,运行窗口被关闭)后此子线程也结束,否则主进程结束子进程不结束,如下所示:

import tkinter as tk import threading class GUI: def __init__(self): self.root = tk.Tk() self.root.title('Title') self.root.geometry("600x300+550+300") self.interface() def interface(self): """"界面编写位置""" self.Button0 = tk.Button(self.root, text="确定", command=self.start) self.Button0.grid(row=0, column=0) self.w1 = tk.Text(self.root, width=80, height=10) self.w1.grid(row=1, column=0) def event(self): '''按钮事件,一直循环''' a = 0 while True: a += 1 self.w1.insert(1.0, str(a) + '\n') def start(self): self.T = threading.Thread(target=self.event) # 多线程 self.T.setDaemon(True) # 线程守护,即主进程结束后,此线程也结束。否则主进程结束子进程不结束 self.T.start() # 启动 if __name__ == '__main__': gui = GUI() gui.root.mainloop()

运行效果如下所示:

在这里插入图片描述

子线程的暂停与重启

除了结束主进程以结束守护线程外,还可以通过 threading.event() 的相关方法来实现守护线程的暂停和继续。改写为如下所示的代码:

import tkinter as tk import threading import time class GUI: def __init__(self): self.root = tk.Tk() self.root.title('Title') self.root.geometry("600x300+550+300") self.interface() self.flag = threading.Event() def interface(self): """"界面编写位置""" self.Button0 = tk.Button(self.root, text="启动", command=self.start) self.Button0.grid(row=0, column=0) self.Button1 = tk.Button(self.root, text="暂停", command=self.stop) self.Button1.grid(row=0, column=1) self.Button2 = tk.Button(self.root, text="继续", command=self.conti) self.Button2.grid(row=0, column=2) self.w1 = tk.Text(self.root, width=70, height=10) self.w1.grid(row=1, column=0, columnspan=3) def event(self): '''按钮事件,一直循环''' while True: time.sleep(1) self.flag.wait() # 只有在internal flag为true时,继续运行子线程 self.w1.insert(1.0, '运行中' + '\n') def start(self): self.flag.set() # 将internal flag设为true,运行子线程 self.T = threading.Thread(target=self.event) self.T.setDaemon(True) self.T.start() def stop(self): self.flag.clear() # 将internal flag设为false,子线程被block self.w1.insert(1.0, '暂停' + '\n') def conti(self): self.flag.set() # 将internal flag设为true,运行子线程 self.w1.insert(1.0, '继续' + '\n') if __name__ == '__main__': gui = GUI() gui.root.mainloop()

运行效果如下所示:

在这里插入图片描述

Tkinter 文件之间调用 准备工作a.py 文件 - - 界面逻辑 + 线程b.py 文件 - - 业务逻辑

以上文件在同一个目录下

方法 以下面的代码块为例,

a.py 的代码如下所示:

import tkinter as tk import threading from b import logic global flag, input, output class GUI: def __init__(self): self.root = tk.Tk() self.root.title('example') self.root.geometry("500x300+500+150") self.interface() self.flag = threading.Event() def interface(self): """"界面编写位置""" self.Button0 = tk.Button(self.root, text="start", command=self.start, bg="#7bbfea") self.Button0.place(x=50, y=15, width=70, height=30) self.Button1 = tk.Button(self.root, text="stop", command=self.stop, bg="#7bbfea") self.Button1.place(x=150, y=15, width=70, height=30) self.Button2 = tk.Button(self.root, text="continue", command=self.conti, bg="#7bbfea") self.Button2.place(x=250, y=15, width=70, height=30) self.Button3 = tk.Button(self.root, text="clear", command=self.clear, bg="#7bbfea") self.Button3.place(x=350, y=15, width=70, height=30) label = tk.Label(text='Input') label.place(x=50, y=70) self.entry00 = tk.StringVar() self.entry00.set("Please give a number here") self.entry0 = tk.Entry(self.root, textvariable=self.entry00) self.entry0.place(x=100, y=70, width=300, height=30) self.entry0.bind('', self.delete) label = tk.Label(text='Output') label.place(x=50, y=180) self.w1 = tk.Text(self.root) self.w1.place(x=100, y=120, width=300, height=170) self.output = self.w1 def seal(self): self.input = self.entry00.get() logic(self.flag, self.input, self.output).event() def clear(self): self.w1.delete('0.0', 'end') def start(self): ''' set internal flag to True and start threading :return: ''' self.flag.set() self.T = threading.Thread(target=self.seal) self.T.setDaemon(True) self.T.start() def stop(self): logic(self.flag, self.input, self.output).stop() def conti(self): logic(self.flag, self.input, self.output).conti() def delete(self, event): self.entry0.delete(0, tk.END) if __name__ == '__main__': a = GUI() a.root.mainloop()

b.py 的代码如下所示:

import threading import time class logic: def __init__(self, flag, input, output): self.flag = flag self.input = input self.output = output def main(self, x): ''' block calling until timeout occurs or internal flag is set to True :return: ''' while True: self.flag.wait() y = int(self.input)+int(x) self.output.insert(1.0, threading.current_thread().name + ': ' + str(y) + '\n') time.sleep(1) x += 1 def stop(self): ''' reset internal flag to False -> threading block calling wait() :return: ''' self.flag.clear() self.output.insert(1.0, f'stopped? {threading.current_thread().is_alive()}' + '\n') # def conti(self): ''' set internal flag to True -> calling wait() :return: ''' self.flag.set() self.output.insert(1.0, f'continued? {threading.current_thread().is_alive()}' + '\n') def event(self): '''main所调用的方法''' x = 1 self.main(x)

运行效果如下所示:

在这里插入图片描述

2个文件中的变量或者函数的相互引用,需要注意避免 circular import。详情参考 2’ 3。

参考链接

python之Tkinter使用详解 ↩︎

ImportError: cannot import name ‘…’ from partially initialized module ‘…’ (most likely due to a circular import) ↩︎

【ModuleNotFoundError 与 ImportError】之 most likely due to a circular import ↩︎



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有